#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Cron表达式解析器
支持标准的cron表达式格式：* * * * * *
分钟 小时 日期 月份 星期 命令
"""

import re
from datetime import datetime, timedelta
from typing import List, Tuple, Optional


class CronParser:
    """Cron表达式解析器类"""

    def __init__(self, cron_expression: str):
        """
        初始化Cron解析器

        Args:
            cron_expression: cron表达式，如 "*/5 * * * * *" 或 "0 9 * * 1-5"
        """
        self.cron_expression = cron_expression.strip()
        self.fields = self._parse_expression()

    def _parse_expression(self) -> List[List[int]]:
        """
        解析cron表达式

        Returns:
            每个字段的允许值列表：[分钟, 小时, 日期, 月份, 星期, 秒]
        """
        parts = self.cron_expression.split()
        if len(parts) < 5:
            raise ValueError("Cron表达式至少需要5个字段（分钟 小时 日期 月份 星期）")

        # 补全秒字段，如果没有的话
        if len(parts) == 5:
            parts.insert(0, "0")  # 在开头插入秒字段

        if len(parts) != 6:
            raise ValueError("Cron表达式格式错误，应为：秒 分 时 日 月 周")

        fields = []
        field_names = ['second', 'minute', 'hour', 'day', 'month', 'weekday']
        field_ranges = [(0, 59), (0, 59), (0, 23), (1, 31), (1, 12), (0, 6)]

        for i, (part, (min_val, max_val), name) in enumerate(zip(parts, field_ranges, field_names)):
            field_values = self._parse_field(part, min_val, max_val, name)
            fields.append(field_values)

        return fields

    def _parse_field(self, field: str, min_val: int, max_val: int, field_name: str) -> List[int]:
        """
        解析单个字段

        Args:
            field: 字段字符串
            min_val: 最小值
            max_val: 最大值
            field_name: 字段名称（用于错误信息）

        Returns:
            该字段的允许值列表
        """
        if field == '*':
            return list(range(min_val, max_val + 1))

        values = set()

        # 分割多个值（用逗号分隔）
        for part in field.split(','):
            part = part.strip()
            if not part:
                continue

            # 处理范围（如 1-5）
            if '-' in part:
                start_str, end_str = part.split('-', 1)
                try:
                    start = int(start_str)
                    end = int(end_str)
                    if start > end:
                        raise ValueError(f"{field_name}字段范围无效: {start}-{end}")
                    values.update(range(max(min_val, start), min(max_val, end) + 1))
                except ValueError as e:
                    raise ValueError(f"{field_name}字段格式错误: {part}") from e

            # 处理步长（如 */5 或 1-10/2）
            elif '/' in part:
                base_part, step_str = part.split('/', 1)
                try:
                    step = int(step_str)
                    if step <= 0:
                        raise ValueError(f"{field_name}字段步长必须大于0: {step}")
                except ValueError as e:
                    raise ValueError(f"{field_name}字段步长格式错误: {step_str}") from e

                if base_part == '*':
                    base_values = list(range(min_val, max_val + 1))
                elif '-' in base_part:
                    start_str, end_str = base_part.split('-', 1)
                    start = int(start_str)
                    end = int(end_str)
                    base_values = list(range(max(min_val, start), min(max_val, end) + 1))
                else:
                    # 单个值作为基础
                    base_val = int(base_part)
                    if base_val < min_val or base_val > max_val:
                        raise ValueError(f"{field_name}字段值超出范围: {base_val}")
                    base_values = [base_val]

                # 应用步长
                for i in range(0, len(base_values), step):
                    values.add(base_values[i])

            # 处理单个值
            else:
                try:
                    val = int(part)
                    if val < min_val or val > max_val:
                        raise ValueError(f"{field_name}字段值超出范围: {val}")
                    values.add(val)
                except ValueError as e:
                    raise ValueError(f"{field_name}字段格式错误: {part}") from e

        return sorted(list(values))

    def get_next_run_time(self, from_time: Optional[datetime] = None) -> datetime:
        """
        获取下次运行时间

        Args:
            from_time: 起始时间，如果为None则使用当前时间

        Returns:
            下次运行时间
        """
        if from_time is None:
            from_time = datetime.now()

        # 从下一秒开始查找
        current = from_time.replace(microsecond=0) + timedelta(seconds=1)

        # 查找匹配的时间（最多查找1年）
        max_attempts = 365 * 24 * 60 * 60  # 1年的秒数
        attempts = 0

        while attempts < max_attempts:
            if self._matches_time(current):
                return current

            current += timedelta(seconds=1)
            attempts += 1

        raise ValueError("无法找到有效的下次运行时间")

    def _matches_time(self, dt: datetime) -> bool:
        """
        检查时间是否匹配cron表达式

        Args:
            dt: 要检查的时间

        Returns:
            是否匹配
        """
        second, minute, hour, day, month, weekday = self.fields

        return (dt.second in second and
                dt.minute in minute and
                dt.hour in hour and
                dt.day in day and
                dt.month in month and
                dt.weekday() in weekday)

    def get_schedule_description(self) -> str:
        """
        获取cron表达式的可读描述

        Returns:
            描述字符串
        """
        second, minute, hour, day, month, weekday = self.fields

        descriptions = []

        # 秒
        if len(second) == 60:
            sec_desc = "每秒"
        elif len(second) <= 5:
            sec_desc = f"{','.join(map(str, second))}秒"
        else:
            sec_desc = f"{second[0]}-{second[-1]}秒"

        # 分钟
        if len(minute) == 60:
            min_desc = "每分钟"
        elif len(minute) <= 5:
            min_desc = f"{','.join(map(str, minute))}分"
        else:
            min_desc = f"{minute[0]}-{minute[-1]}分"

        # 小时
        if len(hour) == 24:
            hour_desc = "每小时"
        elif len(hour) <= 5:
            hour_desc = f"{','.join(map(str, hour))}点"
        else:
            hour_desc = f"{hour[0]}-{hour[-1]}点"

        # 日期
        if len(day) == 31:
            day_desc = "每天"
        elif len(day) <= 5:
            day_desc = f"{','.join(map(str, day))}日"
        else:
            day_desc = f"{day[0]}-{day[-1]}日"

        # 月份
        if len(month) == 12:
            month_desc = "每月"
        elif len(month) <= 5:
            month_desc = f"{','.join(map(str, month))}月"
        else:
            month_desc = f"{month[0]}-{month[-1]}月"

        # 星期
        weekday_names = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
        if len(weekday) == 7:
            week_desc = "每周"
        elif len(weekday) <= 3:
            week_desc = f"{','.join([weekday_names[w] for w in weekday])}"
        else:
            week_desc = f"{weekday_names[weekday[0]]}到{weekday_names[weekday[-1]]}"

        return f"{month_desc}{day_desc} {week_desc} {hour_desc}{min_desc}{sec_desc}"


def validate_cron_expression(cron_expression: str) -> bool:
    """
    验证cron表达式是否有效

    Args:
        cron_expression: cron表达式

    Returns:
        是否有效
    """
    try:
        CronParser(cron_expression)
        return True
    except:
        return False


def get_cron_examples() -> List[Tuple[str, str]]:
    """
    获取cron表达式示例

    Returns:
        示例列表，每个元素为 (表达式, 描述)
    """
    examples = [
        ("* * * * * *", "每秒执行"),
        ("*/5 * * * * *", "每5秒执行"),
        ("0 * * * * *", "每分钟的0秒执行"),
        ("0 */5 * * * *", "每5分钟执行"),
        ("0 0 * * * *", "每天的0点0分0秒执行"),
        ("0 9 * * 1-5 *", "工作日的上午9点执行"),
        ("0 0 1 * * *", "每月1号的0点0分执行"),
        ("0 0 * * 0 *", "每周日的0点0分执行"),
        ("0 30 9 * * 1,3,5 *", "周一、三、五的上午9点30分执行"),
    ]
    return examples


if __name__ == "__main__":
    # 测试代码
    test_expressions = [
        "* * * * * *",
        "*/5 * * * * *",
        "0 9 * * 1-5 *",
        "0 0 1 * * *",
        "0 30 9 * * 1,3,5 *",
    ]

    print("Cron表达式解析测试:")
    for expr in test_expressions:
        try:
            parser = CronParser(expr)
            print(f"表达式: {expr}")
            print(f"描述: {parser.get_schedule_description()}")
            next_time = parser.get_next_run_time()
            print(f"下次运行: {next_time}")
            print("-" * 50)
        except Exception as e:
            print(f"表达式 {expr} 错误: {e}")
            print("-" * 50)
